package com.jintian.smart.kernel.autoconfigure.model;

import com.jintian.smart.kernel.autoconfigure.beetl.BeetlTemplateProvider;
import com.jintian.smart.kernel.common.util.StringUtil;
import com.jintian.smart.kernel.core.annotation.beetl.BeetlFunction;
import lombok.extern.slf4j.Slf4j;
import org.beetl.core.Format;
import org.beetl.core.Function;
import org.beetl.core.GroupTemplate;
import org.beetl.core.fun.FunctionWrapper;
import org.beetl.ext.spring6.BeetlGroupUtilConfiguration;
import org.beetl.sql.core.ConditionalSQLManager;
import org.beetl.sql.core.SQLManager;
import org.beetl.sql.core.engine.SQLPlaceholderST;
import org.beetl.sql.core.engine.template.BeetlTemplateEngine;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;

import java.lang.reflect.Field;
import java.util.*;

@Slf4j
public class BeetlGroupTemplateProcesser {
    protected void copyBeetlGroupTemplateToSqlManager(ApplicationContext masterContext) {
        GroupTemplate sourceGroupTemplate = masterContext.getBean(BeetlGroupUtilConfiguration.class).getGroupTemplate();
        masterContext.getBeansOfType(SQLManager.class).values().forEach(sqlManager -> {
            if (sqlManager instanceof ConditionalSQLManager) {
                return;
            }
            BeetlTemplateEngine beetlTemplateEngine = (BeetlTemplateEngine) sqlManager.getSqlTemplateEngine();
            GroupTemplate targetGroupTemplate = beetlTemplateEngine.getBeetl().getGroupTemplate();
            copyGroupTemplate(sourceGroupTemplate, targetGroupTemplate);
        });
    }

    /**
     * 添加用户自定义function和format到BeetlConfig的GroupTemplate中，用于非SQLManager的模板，例如html
     * todo 原来是是注册非SQLManager的模板，后续调整，注册SQLManager模板
     */
    protected void processBeetlGroupTemplate(ApplicationContext scanContext, GroupTemplate groupTemplate) {
//        ((ConfigurableApplicationContext) scanContext).getBeanFactory().getBeanDefinition("beetlConfig");
//        GroupTemplate groupTemplate = beetlGroupUtilConfiguration.getGroupTemplate();
        Set<String> beetlFnSet = scanBeetlFunction(scanContext, groupTemplate);
        if (beetlFnSet.size() > 0) {
            StringBuffer sb = new StringBuffer("注册").append(scanContext.getId()).append(".beetl模板函数:\n----------------------------------------------------------\n");
            sb.append(StringUtil.join(beetlFnSet.toArray(new String[0]), ","));
            log.info("{}\n----------------------------------------------------------", sb.toString());
        }
        if (scanContext.getParent() != null) {
            // 3. 拷贝主到子项目
            GroupTemplate parentGroupTemplate = scanContext.getParent().getBean(BeetlGroupUtilConfiguration.class).getGroupTemplate();
            copyGroupTemplate(parentGroupTemplate, groupTemplate);
        }
    }

    protected Set<String> scanBeetlFunction(ApplicationContext scanContext, GroupTemplate groupTemplate) {
        // 1.扫描目标Context中的BeetlFunction，并注册到GroupTemplate中
        Set<String> beetlFnSet = new HashSet<>();
        Map<String, Object> beans = scanContext.getBeansWithAnnotation(BeetlFunction.class);
        for (Object obj : beans.values()) {
            BeetlFunction desc = AnnotationUtils.findAnnotation(obj.getClass(), BeetlFunction.class);
            if (obj instanceof Function && !desc.asPackage()) {
                beetlFnSet.add(desc.code());
                groupTemplate.registerFunction(desc.code(), (Function) obj);
                if (desc.placeHolder()) {
                    SQLPlaceholderST.textFunList.add(desc.code());
                }
            } else {
                groupTemplate.registerFunctionPackage(desc.code(), obj);
                List<FunctionWrapper> list = FunctionWrapper.getFunctionWrapper(desc.code(), obj.getClass(), obj);
                for (FunctionWrapper fw : list) {
                    beetlFnSet.add(fw.functionName);
                    if (desc.placeHolder()) {
                        SQLPlaceholderST.textFunList.add(fw.functionName);
                    }
                }
            }
        }

        // 2.注册自定函数和Format
        Collection<BeetlTemplateProvider> list = scanContext.getBeansOfType(BeetlTemplateProvider.class).values();
        list.forEach(p -> {
            Map<String, Function> functions = p.getFunctions();
            functions.forEach((name, fn) -> {
                beetlFnSet.add(name);
                groupTemplate.registerFunction(name, fn);
            });
            Map<String, Format> formats = p.getFormats();
            formats.forEach((name, format) -> {
                groupTemplate.registerFormat(name, format);
            });
        });
        return beetlFnSet;
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    protected static void copyGroupTemplate(GroupTemplate source, GroupTemplate target) {
        try {
            {
                Field filed = GroupTemplate.class.getDeclaredField("fnMap");
                filed.setAccessible(true);

                Map<String, Object> targetFnMap = (Map<String, Object>) filed.get(target);
                Map<String, Object> backup = new HashMap<>();
                backup.putAll(targetFnMap);

                Map sourceFnMap = (Map) filed.get(source);
                targetFnMap.putAll(sourceFnMap);
                targetFnMap.putAll(backup);
            }

            {
                Field filed = GroupTemplate.class.getDeclaredField("formatMap");
                filed.setAccessible(true);

                Map targetFormatMap = (Map) filed.get(target);
                Map backup = new HashMap<>();
                backup.putAll(targetFormatMap);

                Map sourceFormatMap = (Map) filed.get(source);
                targetFormatMap.putAll(sourceFormatMap);
                targetFormatMap.putAll(backup);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}
